package cn.tedu.mall.seckill.init;

import cn.tedu.mall.pojo.seckill.vo.SeckillSkuVO;
import cn.tedu.mall.pojo.seckill.vo.SeckillSpuVO;
import cn.tedu.mall.seckill.mapper.SeckillSkuMapper;
import cn.tedu.mall.seckill.mapper.SeckillSpuMapper;
import cn.tedu.mall.seckill.service.impl.SeckillSkuServiceImpl;
import cn.tedu.mall.seckill.service.impl.SeckillSpuServiceImpl;
import cn.tedu.mall.seckill.utils.RedisBloomUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Random;

@Component
@Slf4j
public class SeckillInitializer {
    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private SeckillSpuMapper seckillSpuMapper;

    @Autowired
    private SeckillSkuMapper seckillSkuMapper;

    //初始化数据,每一种数据,单独做一个方法
    //spu sku
    public void initStart() {
        //从spu开始
        initSpus();
    }

    @Autowired
    private RedisBloomUtils redisBloomUtils;

    private void initSpus() {
        //从数据库 查询所有秒杀的spu select * from seckill_spu
        List<SeckillSpuVO> seckillSpuVOS = seckillSpuMapper.selectAll();
        if (seckillSpuVOS == null || seckillSpuVOS.size() == 0) {
            log.error("当前数据库没有spu预热的数据,请检查数据库");
            return;
        }
        //将这个列表,封装成List<SeckillSpuVO>对象放到缓存
        ValueOperations valueOperations = redisTemplate.opsForValue();
        valueOperations.set(SeckillSpuServiceImpl.SECKILL_SPUS_KEY, seckillSpuVOS);
        //将每个SeckillSpuVO放到缓存
        for (SeckillSpuVO seckillSpuVO : seckillSpuVOS) {
            Long spuId = seckillSpuVO.getId();
            //先将该数据spuId放到布隆过滤器保证判断存在和不存在的功能正确执行
            redisBloomUtils.bfadd(SeckillSpuServiceImpl.SECKILL_BLOOM_SPUS_KEY, spuId + "");
            //生成每个spu秒杀下单提交路径 格式 seckill/{randCode}
            String url = "/seckill/" + (new Random().nextInt(9000) + 1000);
            seckillSpuVO.setUrl(url);
            valueOperations.set(SeckillSpuServiceImpl.SECKILL_SPU_PREFIX + spuId, seckillSpuVO);
            initSkus(spuId);
        }
    }

    private void initSkus(Long spuId) {
        //从数据库先查询sku select * from seckill_sku where spu_id=#{spuId}
        List<SeckillSkuVO> seckillSkuVOS = seckillSkuMapper.selectSkuBySpuId(spuId);
        if (seckillSkuVOS == null || seckillSkuVOS.size() == 0) {
            log.error("秒杀sku数据为空,请检查数据库");
            return;
        }
        //放到预热的缓存中
        ValueOperations valueOperations = redisTemplate.opsForValue();
        String skusKey = SeckillSkuServiceImpl.SECKILL_SKUS_PREFIX + spuId;
        valueOperations.set(skusKey, seckillSkuVOS);
    }

    /**
     * 定时同步库存,每5秒钟执行一次
     */
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    private boolean startTimer = true;

    public void syncStock() {
        while (startTimer) {
            try {
                log.debug("定时执行redis库存重置");
                //读取sku的数据库秒杀stock 读取sku的所有数据 id作为key值 stock作为value值
                //select * from seckill_sku
                List<SeckillSkuVO> skus = seckillSkuMapper.selectAll();
                //存放到set 重置到redis对应库存数据中
                for (SeckillSkuVO seckillSkuVO : skus) {
                    //seckill:sku:stock:1 - 100
                    String skuStockKey =
                            SeckillSkuServiceImpl.SECKILL_SKU_STOCK_PREFIX +
                                    seckillSkuVO.getId();
                    stringRedisTemplate.
                            opsForValue().set(
                            skuStockKey, seckillSkuVO.getStock() + "");
                }
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
